function Foo() {
    this.name = '墨杉' // this可以连接实例对象的属性
}
Foo.a = 1 // 函数本身的属性不会被实例继承
let obj = new Foo()
console.log(obj.a, obj.name) // undefined '墨杉'
console.log(obj.constructor) // Foo 构造器
console.dir(Foo) // 可以看到它有一个prototype属性 就是Foo的基因库

Foo.prototype.sayName = function () {
    console.log(this.name)
}

obj.sayName()

// prototype的好处
// 业务需求： 在数组中添加一百个对象，并且给每一个对象都添加一条属性 state：'交流过了'

const arr = []
for (let i = 0; i < 100; i++) {
    arr.push(new Foo())
}
Foo.prototype.state = '交流过了'
console.log(arr[66].state) // 交流过了

// 给所有的数组添加一个自己的方法

Array.prototype.lalala = function () {
    console.log('啦啦啦！')
}

const brr = []
console.log(brr.lalala()) // 啦啦啦

// new的封装
// new 方法做了哪些事：
/*
    1.创建一个空对象，并使得空对象继承构造函数的原型对象
    2.执行构造函数，将this指向这个新对象；
    3.返回新对象
*/
function myNew(Fn, ...args) {

    const obj = Object.create(Fn.prototype)

    Fn.apply(obj, args)

    return obj
}

function Person(name = '张三', age = 18) {
    this.name = name
    this.age = age
}
Person.prototype.sayName = function () {
    console.log(this.name)
}

const xm = myNew(Person, '小明', 18)
console.log(xm) // {name: "小明", age: 18}
xm.sayName() // 小明

console.log(myNew(Person)) // {name: "张三", age: 18}

// 原型开发 给数组实现一个自己的reduce方法
Array.prototype.myReduce = function (cb, init) {
    // 统计结果
    let total = 0

    // 传入初始值就用初始值 没有就为0
    if (typeof init === 'undefined') {
        return NaN
    }

    if (init) {
        total = init
    }

    // 统计所有元素操作之后的结果
    for (let i = 0; i < this.length; i++) {
        total = cb(total, this[i], i, this)
    }
    // 将结果返回
    return total
}

const crr = [1, 2, 3]
console.log(crr.myReduce((t, c) => t + c, 4)) // 10

// 封装一个判断数据了类型的方法
function type(v) {
    return Object.prototype.toString.call(v).slice(8, -1)
}
console.log(type([1, 2, 3])) // Array

class Pe {
    constructor(x, y) {
        this.a = x
        this.b = y
    }
    f1() {
        console.log(this.a)
    }
    f2(z) {
        console.log(this.b + z)
    }
}

let oo = new Pe(2, 3)
oo.f1() // 2
oo.f2(2) // 5

// 继承
class Fe extends Pe {
    constructor(x, y, a) {
        super(x, y)
        this.c = a
    }
    f3() {
        console.log(this.a + this.b + this.c)
    }

    // 静态方法
    static saySome() {
        console.log('你好，我是静态方法！')
    }
}

let ooo = new Fe(1, 2, 3)
ooo.f1() // 1
ooo.f2(2) // 4
ooo.f3() // 6
// ooo.saySome() 对象实例无法执行静态方法
Fe.saySome() // 只允许构造函数执行